package com.vincent.template.commons.validation.validators;

import com.vincent.template.commons.validation.constraints.UniqueEntity;
import com.vincent.template.utils.FieldUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.ValidationException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author Vincent Wang
 * @Date 2020/11/4 14:00
 */
public class UniqueEntityValidator implements ConstraintValidator<UniqueEntity, List<?>> {

    private String[] fields;
    boolean ignoreAllEmpty;

    @Override
    public void initialize(UniqueEntity constraintAnnotation) {
        fields = constraintAnnotation.fields();
        ignoreAllEmpty = constraintAnnotation.ignoreAllEmpty();
    }

    @Override
    public boolean isValid(List<?> list, ConstraintValidatorContext constraintValidatorContext) {
        if (CollectionUtils.isEmpty(list) || list.size() == 1) {
            return true;
        }
        try {
            Class<?> clazz = list.get(0).getClass();
            List<Method> methods = new ArrayList<>();
            for (String field : fields) {
                methods.add(clazz.getMethod(FieldUtil.getMethodName(field)));
            }
            Set<String> set = new HashSet<>();
            int allEmptyCount = 0;
            for (Object obj : list) {
                StringBuilder sb = new StringBuilder();
                for (Method method : methods) {
                    Object value = method.invoke(obj);
                    if (value != null) {
                        sb.append(method.getName()).append(value);
                    }
                }
                String splicedStr = String.valueOf(sb);
                if (StringUtils.isBlank(splicedStr)) {
                    allEmptyCount++;
                }
                set.add(splicedStr);
            }
            if (ignoreAllEmpty) {
                if (allEmptyCount > 0) {
                    allEmptyCount--;
                }
                return set.size() + allEmptyCount == list.size();
            }
            return set.size() == list.size();
        } catch (Exception e) {
            throw new ValidationException(e.getMessage());
        }
    }
}
